Skip to content

Conversation

@matteo8p
Copy link
Collaborator

@matteo8p matteo8p commented Dec 15, 2025

This PR proposes a fix to the 0.0.0.0 day vulnerability where localhost applications are vulnerable to remote code execution. We add a PNA pre-flight with verification to reject requests from unverified origins.

#1095

  • Add centralized CORS/host utility that enforces the localhost allowlist and builds consistent headers (including PNA
    support).
  • Reject requests with disallowed Host/Origin early and answer preflights only for trusted origins.
  • Replace wildcard CORS on MCP HTTP/SSE/elicitation endpoints with allowlisted, credentials-aware responses.

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Dec 15, 2025
@matteo8p
Copy link
Collaborator Author

This is one remediation strategy, but I actually don't think we need to take action here because browsers now should already handle the 0.0.0.0 day vulnerability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 15, 2025

Walkthrough

This change implements a centralized CORS handling system across the server. A new cors.ts utility module provides functions for origin validation, hostname verification, and dynamic CORS header construction. These utilities are integrated throughout the codebase—in the main server entry point, HTTP adapters, and MCP route handlers—replacing static CORS headers with origin-aware dynamic responses. Request filtering is added via host and origin validation middleware that blocks disallowed requests with 403 responses. Preflight handlers for OPTIONS requests are introduced to validate origins early in the request lifecycle.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/routes/mcp/servers.ts (1)

110-113: Use centralized logger instead of console.debug.

Per coding guidelines, server code should use the centralized logger utility rather than console.* directly.

-      console.debug(
-        `Failed to disconnect MCP server ${serverId} during removal`,
-        error,
-      );
+      logger.debug(
+        `Failed to disconnect MCP server ${serverId} during removal`,
+        error,
+      );
🧹 Nitpick comments (4)
server/utils/cors.ts (1)

3-11: Export CorsOptions type for external consumers.

The CorsOptions type is used by callers of buildCorsHeaders but isn't exported. Consider exporting it so consumers can type their options objects explicitly.

-type CorsOptions = {
+export type CorsOptions = {
   allowCredentials?: boolean;
   allowHeaders?: string;
   allowMethods?: string;
   exposeHeaders?: string;
   maxAge?: string;
   requestPrivateNetwork?: boolean;
   allowPrivateNetwork?: boolean;
 };
server/routes/mcp/elicitation.ts (1)

52-56: Consider blocking SSE streams for disallowed origins.

Currently, if getAllowedOrigin returns null, the response proceeds without Access-Control-Allow-Origin. While browsers will block cross-origin access to the response, the SSE connection itself is still established and data flows server-side.

For defense-in-depth, you may wish to explicitly reject disallowed origins early:

   const originHeader = c.req.header("origin");
   const { headers: corsHeaders } = buildCorsHeaders(originHeader, {
     allowCredentials: true,
   });
+  if (originHeader && !corsHeaders["Access-Control-Allow-Origin"]) {
+    return c.json({ error: "Origin not allowed" }, 403, { Vary: "Origin" });
+  }
server/index.ts (1)

235-241: Consider the interaction between manual validation and cors() middleware.

The manual middleware (Lines 154-174) blocks disallowed origins, while this cors() middleware adds CORS headers. Both reference CORS_ORIGINS, which is good for consistency. However, the manual validation now renders some of this middleware's origin checking redundant.

This layered approach is safe, though consolidating into a single CORS strategy could reduce complexity in the future.

server/routes/mcp/http-adapters.ts (1)

80-86: Remove shadowed originHeader declaration.

The originHeader variable is already declared at line 50 and accessible here. This redeclaration shadows the outer variable unnecessarily.

         // Compute an absolute endpoint based on forwarded headers when present
         // so direct access (without the proxy) advertises a reachable URL.
         const xfProto = c.req.header("x-forwarded-proto");
         const xfHost = c.req.header("x-forwarded-host");
         const host = xfHost || c.req.header("host");
         let proto = xfProto;
         if (!proto) {
-          const originHeader = c.req.header("origin");
           if (originHeader && /^https:/i.test(originHeader)) proto = "https";
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae765dd and 2d0fe92.

📒 Files selected for processing (5)
  • server/index.ts (3 hunks)
  • server/routes/mcp/elicitation.ts (3 hunks)
  • server/routes/mcp/http-adapters.ts (6 hunks)
  • server/routes/mcp/servers.ts (7 hunks)
  • server/utils/cors.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
server/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

server/**/*.{ts,tsx,js,jsx}: Do not use console.log, console.warn, or console.error directly in server code; use the centralized logger utility from @/utils/logger instead
Use centralized logger utility methods: logger.error(), logger.warn(), logger.info(), and logger.debug() from @/utils/logger for server-side logging

Files:

  • server/routes/mcp/elicitation.ts
  • server/index.ts
  • server/utils/cors.ts
  • server/routes/mcp/servers.ts
  • server/routes/mcp/http-adapters.ts
🧬 Code graph analysis (4)
server/routes/mcp/elicitation.ts (1)
server/utils/cors.ts (1)
  • buildCorsHeaders (49-84)
server/utils/cors.ts (1)
server/config.ts (2)
  • CORS_ORIGINS (18-23)
  • SERVER_HOSTNAME (11-12)
server/routes/mcp/servers.ts (2)
server/utils/logger.ts (2)
  • logger (11-53)
  • error (15-23)
server/utils/cors.ts (1)
  • buildCorsHeaders (49-84)
server/routes/mcp/http-adapters.ts (1)
server/utils/cors.ts (1)
  • buildCorsHeaders (49-84)
🔍 Remote MCP

Summary of Additional Context for PR #1096 Review

This PR addresses a critical security vulnerability by implementing strict origin and host validation for localhost-based APIs. Here's the relevant context:

Vulnerability Context

The 0.0.0.0 Day vulnerability allows attackers to use public domains with 0.0.0.0 and "no-cors" mode to attack services running on localhost and gain arbitrary code execution (RCE), using a single HTTP request. The vulnerability affects all major browsers and enables RCE attacks on macOS and Linux devices.

The fix pattern used by ChromeDriver checks the Origin or Host headers and only allows localhost origins (localhost, 127.0.0.1, etc.). This PR implements a similar defensive strategy.

CORS Security Best Practices Applied

The PR's implementation aligns with critical security recommendations:

  1. Origin Validation: The null origin should never be added to allowed domains, as it's used when requests come from privacy-sensitive contexts like sandboxed iframes, which attackers can include in their websites.

  2. Credentials + Origin Restriction: If a request includes a credential (most commonly a Cookie header) and the response includes an Access-Control-Allow-Origin: * header, the browser will block access to the response. If response has Access-Control-Allow-Credentials: true, then the wildcard operator cannot be used on any of the response headers like Access-Control-Allow-Origin.

  3. Wildcard Restrictions: CORS headers should be properly defined in respect of trusted origins for private and public servers, and avoid using wildcards in internal networks.

Private Network Access (PNA) Considerations

The PR adds support for Private Network Access, which is increasingly important:

Private Network Access (PNA) is a security feature that restricts the ability of websites to send requests to servers on private networks, helping protect users and internal networks from potential attacks like Cross-Site Request Forgery (CSRF).

Browsers send a CORS preflight request ahead of any private network request for a subresource, which carries a new header Access-Control-Request-Private-Network: true, and the response must carry a corresponding header Access-Control-Allow-Private-Network: true.

Key Review Points

  • Host Header Validation: The new isAllowedHost() function prevents DNS rebinding attacks by validating the Host header
  • Origin-Based Access Control: The getAllowedOrigin() and buildCorsHeaders() functions ensure only explicitly allowed origins can interact with the endpoints
  • Early Request Filtering: Host/origin validation happens at the middleware level, blocking attacks before they reach business logic
  • Preflight Handling: The new handlePreflight() for OPTIONS requests implements proper CORS preflight responses with origin validation
  • Credentials Flag: The implementation correctly uses allowCredentials: true only after validating origins (never with wildcards)

[web_search]

🔇 Additional comments (8)
server/utils/cors.ts (2)

49-84: Well-structured CORS header construction.

The implementation correctly:

  • Always includes Vary: Origin for proper caching behavior
  • Only sets Access-Control-Allow-Origin for validated origins
  • Never combines credentials with wildcard origins
  • Requires explicit opt-in for Private Network Access

43-47: Clarify the security implications of allowing requests without Host headers.

The function returns true for missing or unparseable hostHeader, which means requests without a Host header bypass the validation check entirely. While this accommodates edge cases (HTTP/1.0 clients, internal tools), it contradicts the middleware's stated security goal of preventing "0.0.0.0 day" attacks that coerce local services into serving cross-origin traffic. Consider whether this permissive default is necessary or if Host headers should be required for validation.

server/routes/mcp/elicitation.ts (1)

90-99: SSE response headers properly applied.

The corsHeaders are correctly spread into the response, maintaining the existing SSE-specific headers while adding origin-aware CORS headers.

server/routes/mcp/servers.ts (1)

206-211: CORS header construction for RPC stream looks correct.

Consistent with the pattern established in elicitation.ts. Same defense-in-depth consideration applies: consider explicitly blocking disallowed origins before establishing the SSE connection.

server/index.ts (2)

151-174: Solid host and origin validation middleware.

This effectively mitigates the 0.0.0.0 day vulnerability by:

  • Checking x-forwarded-host before host for proxy compatibility
  • Blocking requests with disallowed Host headers early
  • Rejecting requests with unauthorized Origins before they reach handlers

250-268: Preflight handler properly validates origin and supports PNA.

The implementation correctly:

  • Blocks preflights from unauthorized origins with 403
  • Supports Private Network Access headers
  • Appends to Vary header appropriately
server/routes/mcp/http-adapters.ts (2)

20-40: Well-implemented preflight handler with origin validation.

The handlePreflight function correctly rejects unauthorized origins with 403 and supports PNA headers. Reusing this for both /:serverId and /:serverId/* routes is clean.


47-65: Comprehensive CORS headers across all response paths.

The corsHeaders are consistently applied to HEAD, GET, POST, and error responses. This ensures browsers receive proper CORS headers regardless of the request outcome.

@matteo8p matteo8p force-pushed the prevent-rce-attacks branch from 2d0fe92 to 264f107 Compare December 30, 2025 22:14
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Dec 30, 2025
@matteo8p matteo8p force-pushed the prevent-rce-attacks branch from 264f107 to 1966067 Compare December 30, 2025 22:41
@matteo8p matteo8p closed this Jan 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants